package study.alex.resumedb.gae;

import com.google.appengine.api.backends.BackendService;
import com.google.appengine.api.backends.BackendServiceFactory;
import com.google.appengine.api.urlfetch.*;
import com.google.appengine.api.users.UserServiceFactory;
import com.vaadin.addon.jpacontainer.EntityItem;
import com.vaadin.addon.jpacontainer.JPAContainerFactory;
import com.vaadin.addon.jpacontainer.JPAContainerItem;
import com.vaadin.addon.jpacontainer.provider.CachingMutableLocalEntityProvider;
import com.vaadin.addon.jpacontainer.util.DefaultQueryModifierDelegate;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.data.util.filter.And;
import com.vaadin.data.util.filter.Compare;
import com.vaadin.data.validator.EmailValidator;
import com.vaadin.data.validator.RegexpValidator;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.*;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.BorderStyle;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Runo;
import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;
import study.alex.resumedb.gae.backend.Broadcaster;
import study.alex.resumedb.gae.feeds.VacancyFeed;
import study.alex.resumedb.gae.feeds.VacancyFeedFactory;
import study.alex.resumedb.gae.model.*;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import javax.persistence.criteria.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainViewPanel extends Panel implements View, Serializable, Broadcaster.BroadcastListener {

    public final static Logger log = Logger.getLogger(MainViewPanel.class.getName());
    private final static int MAX_URI_FRAGMENTS_LENGTH = 300;
    private final UI parent;
    private final String rootUrl;
    private final String userId;
    private final GoogleServices services;
    private Label statusbar;
    private Mine mine;
    @PersistenceContext(unitName = EMF.PERSISTENCE_UNIT, type = PersistenceContextType.EXTENDED)
    transient private EntityManager em;
    private String resumeTableSortColumn;
    private boolean resumeTableSortAsc;
    private TabSheet mainTab = new TabSheet();

    private TabSheet.Tab resumeTab;
    private TabSheet.Tab catalogTab;
    private TabSheet.Tab myInfoTab;
    private TabSheet.Tab todayTab;
    private final MenuBar bar = new MenuBar();
    private final HorizontalLayout highBar = new HorizontalLayout();
    private GridLayout userInfoBar;
    private final HorizontalLayout catalogTabForm = new HorizontalLayout();
    private StringBuffer pageFragments = new StringBuffer();
    private Table resumeTable;
    private Table historyTable;
    private Table contactTable;
    private Component mainContent;
    transient private URLFetchService fetchService = URLFetchServiceFactory.getURLFetchService();
    private final VerticalLayout todayContent = new VerticalLayout();

    private class PanelOfVacancyTrackingSetting extends Panel {

        public PanelOfVacancyTrackingSetting() {
            final VerticalLayout verticalLayout = new VerticalLayout();
            verticalLayout.setSizeFull();
            verticalLayout.setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
            verticalLayout.setSpacing(true);
            verticalLayout.setMargin(true);

            List<String> feedIds = VacancyFeedFactory.getKnownFeeds();
            GridLayout feedTable = new GridLayout(3, feedIds.size());
            feedTable.setSpacing(true);
            feedTable.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
            int row = 0;
            for (String id : feedIds) {
                CheckBox feedCheck = new CheckBox(id);
                VacancyFeed feedInstance = VacancyFeedFactory.getInstance(id);
                if (feedInstance == null)
                    feedCheck.addValueChangeListener(new Property.ValueChangeListener() {
                        @Override
                        public void valueChange(Property.ValueChangeEvent event) {
                            Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("not.implemented.yet"), Notification.Type.HUMANIZED_MESSAGE);
                        }
                    });
                else {
                    feedCheck.setDescription(feedInstance.getDescription());
                }
                TextField keywords = new TextField(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("keywords"));
                keywords.setColumns(35);
                CheckBox complex = new CheckBox(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("complex.request"));
                feedTable.addComponent(feedCheck, 0, row);
                feedTable.addComponent(keywords, 1, row);
                feedTable.addComponent(complex, 2, row++);
            }
            verticalLayout.addComponent(feedTable);
            verticalLayout.setComponentAlignment(feedTable, Alignment.TOP_CENTER);
            setCaption(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("vacancies.tracking"));
            setContent(verticalLayout);
        }
    }

   public MainViewPanel(UI parentWindow, String aUserId, String root, GoogleServices aServices) {
        parent = parentWindow;
        userId = aUserId;
        rootUrl = root;
        this.services = aServices;
        em = JPAContainerFactory.createEntityManagerForPersistenceUnit(EMF.PERSISTENCE_UNIT);

        final Label loading = new Label("<b><i>Loading ...</i></b>", ContentMode.HTML);
        loading.setSizeUndefined();

        final VerticalLayout layout = new VerticalLayout();
        layout.setSizeFull();

        layout.addComponent(loading);
        layout.setComponentAlignment(loading, Alignment.MIDDLE_CENTER);
/*
        if (parent != null) {
            parent.setSizeFull();
            parent.setContent(layout);
        }
*/
       setSizeFull();
       setContent(layout);

        Query q = em.createQuery("SELECT m FROM " + Mine.class.getName() + " m WHERE m.userId='"
                + userId + "'", Mine.class);
        List<Mine> result = q.getResultList();
        if (result == null || result.isEmpty()) {
            log.warning("My Info entity didn't set");
            Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("info.about.user.didn.t.set"),
                    ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("it.will.use.a.clear.data.please.set.the.information.about.you.firstly"),
                    Notification.Type.WARNING_MESSAGE);
            mine = new Mine(userId);
            em.persist(mine);
        } else mine = result.get(0);
    }

    private void readObject(ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
        stream.defaultReadObject();

        // assign reference manually.
        em = JPAContainerFactory.createEntityManagerForPersistenceUnit(EMF.PERSISTENCE_UNIT);
        fetchService = URLFetchServiceFactory.getURLFetchService();
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {


        if (userId == null) {

            Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("firstly.you.need.to.login.via.google"), "", Notification.Type.HUMANIZED_MESSAGE);

            //User didn't login
            UI.getCurrent().getPage().setLocation(rootUrl);
            // Close the VaadinSession
            UI.getCurrent().getSession().close();
            log.fine("User didn't log in");
            return;
        }

        if (mainContent == null) {
            mainContent = createMainContent();
            setContent(mainContent);
        }
        String uriFragment = event.getParameters().substring(0, (event.getParameters().length() > MAX_URI_FRAGMENTS_LENGTH) ? MAX_URI_FRAGMENTS_LENGTH : event.getParameters().length());
        pageFragments = new StringBuffer();
        if (uriFragment != null && !uriFragment.isEmpty()) {
            String[] fragments = uriFragment.split("&");
            log.fine("URI fragments is " + uriFragment + ", view name is " + event.getViewName());
            pageFragments.append(uriFragment);
            if (fragments[0].equals("resumes")) {
                selectResumesFromFragments(fragments);
                mainTab.setSelectedTab(resumeTab);
                Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                log.fine("After select URI fragments is " + pageFragments.toString() + ", view name is " + event.getViewName());
            } else if (fragments[0].equals("contacts")) {
                selectContactFromFragments(fragments);
                mainTab.setSelectedTab(catalogTab);
                Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                log.fine("After select URI fragments is " + pageFragments.toString() + ", view name is " + event.getViewName());
            } else if (fragments[0].equals("myinfo")) {
                mainTab.setSelectedTab(myInfoTab);
                Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                log.fine("After select URI fragments is " + pageFragments.toString() + ", view name is " + event.getViewName());
            } else if (fragments[0].equals("today")) {
                mainTab.setSelectedTab(todayTab);
                Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                log.fine("After select URI fragments is " + pageFragments.toString() + ", view name is " + event.getViewName());
            }
        } else {
            log.fine("Null URI fragments, view name is " + event.getViewName());
            pageFragments.append("today");
            Page.getCurrent().setUriFragment("!/" + "today", false);
        }
    }

    @Override
    public void receiveBroadcast(String message) {
        //TODO update today tab
        log.info("Received broadcast message: " + message);
        if (message.equals("TODO")) {
            if (parent != null) parent.access(new Runnable() {
                @Override
                public void run() {
                    refreshTodayContent();
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("tasks.updated"));
                }
            });
        }
    }

    private void selectContactFromFragments(String[] fragments) {
        if (fragments != null && fragments.length == 2) {
            if (contactTable != null)
                if (fragments[1] != null && !fragments[1].isEmpty()) contactTable.select(fragments[1]);
                else contactTable.select(contactTable.firstItemId());
        }
    }

    private void selectResumesFromFragments(String[] fragments) {
        if (fragments != null && fragments.length == 3) {
            if (resumeTable != null)
                if (fragments[1] != null && !fragments[1].isEmpty()) {
                    resumeTable.select(fragments[1]);
                    if (historyTable != null)
                        if (fragments[2] != null && !fragments[2].isEmpty()) historyTable.select(fragments[2]);
                        else historyTable.select(historyTable.firstItemId());
                }
                else resumeTable.select(resumeTable.firstItemId());
        }
    }

    private Component createMainContent() {

        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        layout.setSpacing(true);
        layout.setCaption("ResumeDB");
        layout.setSizeFull();

        //High menu bar
        highBar.setWidth("100%");
        highBar.setSpacing(true);

        //Main menu
        createMainMenu();

        highBar.addComponent(bar);
        highBar.setComponentAlignment(bar, Alignment.TOP_LEFT);

        //Logged in user info panel (high, right)
        createUserInfoLabel();

        highBar.addComponent(userInfoBar);
        highBar.setComponentAlignment(userInfoBar, Alignment.TOP_RIGHT);
        layout.addComponent(highBar);
        layout.setComponentAlignment(highBar, Alignment.TOP_LEFT);
        layout.setExpandRatio(highBar, 5);

        //Main form (tabbed view)

        mainTab.setSizeFull();

        //TODAY tab

        createTodayTab();

        //Resume tab

        createResumeTab();


        //Catalog tab
        createCatalogTab();


        //Myinfo tab
        CreateMyInfoTab();

        layout.addComponent(mainTab);
        layout.setComponentAlignment(mainTab, Alignment.TOP_CENTER);
        layout.setExpandRatio(mainTab, 92);

        mainTab.addSelectedTabChangeListener(new TabSheet.SelectedTabChangeListener() {
            @Override
            public void selectedTabChange(TabSheet.SelectedTabChangeEvent event) {
                TabSheet sheet = event.getTabSheet();
                TabSheet.Tab tab = sheet.getTab(event.getTabSheet().getSelectedTab());
                if (tab == todayTab) {
                    pageFragments = new StringBuffer("today");
                    Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                }
                else if (tab == resumeTab) {
                    pageFragments = new StringBuffer("resumes");
                    restoreURIFragmentForResume();
                    Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                }
                else if (tab == catalogTab) {
                    pageFragments = new StringBuffer("contacts");
                    restoreURIFragmentForContact();
                    Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                }
                else if (tab == myInfoTab) {
                    pageFragments = new StringBuffer("myinfo");
                    Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
                }
            }
        });

        //Statusbar

        statusbar = new Label("");
        statusbar.setSizeUndefined();

        layout.addComponent(statusbar);
        layout.setComponentAlignment(statusbar, Alignment.MIDDLE_LEFT);
        layout.setExpandRatio(statusbar, 1);

        return layout;
    }

    private void createTodayTab() {

        todayContent.setSizeFull();
        todayContent.setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
        refreshTodayContent();
        todayTab = mainTab.addTab(todayContent, ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("today"));
        todayTab.setClosable(false);
        todayTab.setVisible(true);
    }

    private void restoreURIFragmentForContact() {
        Object ref = contactTable.getValue();
        if (ref != null ) {
            if (ref instanceof String) {
                changeURIFragment(1, (String)ref);
            }
        }
    }

    private void restoreURIFragmentForResume() {

        Object ref1 = historyTable.getValue();
        Object ref2 = resumeTable.getValue();
        if (ref1 != null ) {
            if (ref1 instanceof String) {
                changeURIFragment(2, (String)ref1);
                changeURIFragment(1, (String)ref2);
            }
        } else if (ref2 != null) {
            if (ref2 instanceof String) {
                changeURIFragment(1, (String)ref2);
            }
        }
    }

    private void CreateMyInfoTab() {
        final FormLayout infoTabForm = new FormLayout();
        infoTabForm.setSizeUndefined();
        final BeanFieldGroup<Mine> myInfoBean = new BeanFieldGroup<Mine>(Mine.class);
        myInfoBean.setItemDataSource(mine);

        final Field flName = myInfoBean.buildAndBind(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("full.name"), "name");
        flName.addValidator(new StringLengthValidator(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("names.length.must.be.greater.min"),
                3, 200, false));
        flName.setRequired(true);
        flName.setRequiredError(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("empty.name.isn.t.allowed"));
        final Field flAdr = myInfoBean.buildAndBind(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("address"), "address");
        final Field flPh = myInfoBean.buildAndBind(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("phones"), "phones");
        flPh.addValidator(new RegexpValidator(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("phone.regex"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("invalid.phone.number")));
        flPh.setRequired(true);
        flPh.setRequiredError(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("phone.is.required"));
        final Field flEml = myInfoBean.buildAndBind(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("e.mails"), "emails");
        flEml.addValidator(new EmailValidator(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("invalid.e-mail")));
        flEml.setRequired(true);
        flEml.setRequiredError(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("e.mail.is.required"));
        infoTabForm.addComponent(flName);
        infoTabForm.addComponent(flAdr);
        infoTabForm.addComponent(flPh);
        infoTabForm.addComponent(flEml);
        myInfoBean.setBuffered(true);
        myInfoBean.addCommitHandler(new FieldGroup.CommitHandler() {
            @Override
            public void preCommit(FieldGroup.CommitEvent commitEvent) throws FieldGroup.CommitException {
                log.fine("Validating My info form.  Name is " + commitEvent.getFieldBinder().getField("name").getValue());

                if (!commitEvent.getFieldBinder().isValid()) {
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("input.data.is.not.valid"));
                    throw new FieldGroup.CommitException("Input data is not valid");
                }
            }

            @Override
            public void postCommit(FieldGroup.CommitEvent commitEvent) throws FieldGroup.CommitException {
                EntityManager em = JPAContainerFactory.createEntityManagerForPersistenceUnit(EMF.PERSISTENCE_UNIT);
                em.merge(((BeanItem<Mine>) commitEvent.getFieldBinder().getItemDataSource()).getBean());
                em.close();
                setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("data.saved"));
                log.info("Saved myInfo data to database.  Data is " + mine);
            }
        });
        infoTabForm.setSpacing(true);
        infoTabForm.setSizeUndefined();
        final VerticalLayout infoTabFormWrapper = new VerticalLayout();
        infoTabFormWrapper.setSpacing(true);
        infoTabFormWrapper.setMargin(true);
        infoTabFormWrapper.addComponent(infoTabForm);
        infoTabFormWrapper.setComponentAlignment(infoTabForm, Alignment.TOP_CENTER);

        final HorizontalLayout buttons = new HorizontalLayout();
        buttons.setSpacing(true);
        buttons.setSizeUndefined();
        buttons.addComponent(new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("set"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent clickEvent) {
                try {
                    myInfoBean.commit();
                } catch (FieldGroup.CommitException e) {
                    log.warning("Error while commit bean in MyInfo form");
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("error.while.input.data"));
                }
            }
        }));
        buttons.addComponent(new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("undo"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent clickEvent) {
                myInfoBean.discard();
            }
        }));
        infoTabFormWrapper.addComponent(buttons);
        infoTabFormWrapper.setComponentAlignment(buttons, Alignment.TOP_CENTER);

        final Button clearCredentialButton = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("clear.google.services.access.status"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                ((ResumeDbMainServlet) ResumeDbMainServlet.getCurrent()).dropCredential();
                Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("current.page.needs.to.reload"), Notification.Type.WARNING_MESSAGE);
                Page.getCurrent().setLocation(rootUrl);
            }
        });
        final Label warnReloadMessage = new Label(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("it.needs.to.reload.page.page.reloads.automatically"));
        final HorizontalLayout clearBar = new HorizontalLayout(clearCredentialButton, warnReloadMessage);
        clearBar.setComponentAlignment(warnReloadMessage, Alignment.MIDDLE_LEFT);
        clearBar.setSizeUndefined();
        clearBar.setSpacing(true);
        infoTabFormWrapper.addComponent(clearBar);
        infoTabFormWrapper.setComponentAlignment(clearBar, Alignment.TOP_CENTER);
        infoTabFormWrapper.setSpacing(true);
        infoTabFormWrapper.setMargin(true);

        //Vacancy tracking

        final Panel setVacancyTrackingPanel = new PanelOfVacancyTrackingSetting();
        setVacancyTrackingPanel.setSizeUndefined();
        setVacancyTrackingPanel.setStyleName(Runo.PANEL_LIGHT);
        infoTabFormWrapper.addComponent(setVacancyTrackingPanel);
        infoTabFormWrapper.setComponentAlignment(setVacancyTrackingPanel, Alignment.TOP_CENTER);

        myInfoTab = mainTab.addTab(infoTabFormWrapper, ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("my.info"));
        myInfoTab.setClosable(false);
        myInfoTab.setVisible(true);
    }

    private void createCatalogTab() {
        catalogTabForm.setSizeFull();

        //Contacts List's table

        final BeanFieldGroup<Contact> formItem = new BeanFieldGroup<Contact>(Contact.class);

        contactTable = new ContactTable(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("list.of.contacts"), userId);

        //Detail contact's form

        final FormLayout detailedContactForm = new FormLayout();
        detailedContactForm.setCaption(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("details"));

        if (contactTable.getValue() != null) {
            formItem.setItemDataSource(new BeanItem<Contact>(((JPAContainerItem<Contact>) contactTable.getItem(contactTable.getValue())).getEntity()));
        } else
            formItem.setItemDataSource(new BeanItem<Contact>(new Contact(userId)));

        detailedContactForm.addComponents(formItem.buildAndBind(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("it.s.person"), "personflag", CheckBox.class));

        final TextField nameField = new TextField(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("contact.person.name"));
        formItem.bind(nameField, "name");
        nameField.addValidator(new StringLengthValidator(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("names.length.must.be.greater.min"), 3, 250, false));
        nameField.setRequired(true);
        nameField.setRequiredError(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("name.must.be.not.empty"));
        detailedContactForm.addComponent(nameField);

        detailedContactForm.addComponent(formItem.buildAndBind(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("organization.name"), "organization"));

        final TextField phoneField = new TextField(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("phones"));
        formItem.bind(phoneField, "phones");
        phoneField.addValidator(new RegexpValidator(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("phone.regex"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("invalid.phone.number")));
        phoneField.setRequired(false);
//            nameField.setRequiredError(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("phone.must.be.not.empty"));
        detailedContactForm.addComponent(phoneField);

        final TextField emailField = new TextField(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("e.mails"));
        formItem.bind(emailField, "emails");
        emailField.addValidator(new EmailValidator(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("invalid.e-mail")));
        detailedContactForm.addComponent(emailField);

        final TextArea addressField = new TextArea(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("address"));
        formItem.bind(addressField, "address");
        addressField.setRows(5);
        addressField.setColumns(30);
        addressField.setWordwrap(true);
        detailedContactForm.addComponent(addressField);

        final TextArea commentField = new TextArea(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("comment"));
        formItem.bind(commentField, "comment");
        commentField.setRows(5);
        commentField.setColumns(30);
        commentField.setWordwrap(true);
        detailedContactForm.addComponent(commentField);
        formItem.setBuffered(true);

        final Button saveAsNew = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("save.as.new"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                if (formItem.isValid()) {
                    Contact newContact = new Contact(userId);
                    newContact.setPersonflag((Boolean) formItem.getField("personflag").getValue());
                    newContact.setName((String) formItem.getField("name").getValue());
                    newContact.setOrganization((String) formItem.getField("organization").getValue());
                    newContact.setAddress((String) formItem.getField("address").getValue());
                    newContact.setPhones((String) formItem.getField("phones").getValue());
                    newContact.setEmails((String) formItem.getField("emails").getValue());

                    log.info("Storing new Contact: " + newContact);
                    Object ref = ((JPAContainerForContact) contactTable.getContainerDataSource()).addEntity(newContact);
                    ((JPAContainerForContact) contactTable.getContainerDataSource()).refresh();
                    contactTable.select(ref);
                    if (contactTable.getValue() != null) {
                        formItem.setItemDataSource(new BeanItem<Contact>(((JPAContainerItem<Contact>) contactTable.getItem(contactTable.getValue())).getEntity()));
                    }
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("new.contact.saved"));
                } else
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("invalid.input.data"));
            }
        });
        final Button update = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("update"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                try {
                    log.info("Update Contact: " + formItem.getItemDataSource().getBean());
                    formItem.commit();

                    Object ref = contactTable.getValue();
                    if (ref != null) {
                        EntityItem<Contact> updItem = (JPAContainerItem<Contact>) contactTable.getItem(ref);
                        updItem.setBuffered(true);
                        updItem.getItemProperty("personflag").setValue((Boolean) formItem.getField("personflag").getValue());
                        updItem.getItemProperty("name").setValue((String) formItem.getField("name").getValue());
                        updItem.getItemProperty("organization").setValue((String) formItem.getField("organization").getValue());
                        updItem.getItemProperty("address").setValue((String) formItem.getField("address").getValue());
                        updItem.getItemProperty("phones").setValue((String) formItem.getField("phones").getValue());
                        updItem.getItemProperty("emails").setValue((String) formItem.getField("emails").getValue());
                        updItem.getItemProperty("comment").setValue((String) formItem.getField("comment").getValue());

                        updItem.commit();
                        setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("data.updated"));
                    } else
                        setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("nothing.to.do"));
                } catch (FieldGroup.CommitException e) {
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("input.data.isn.t.valid"));
                }
            }
        });
        final Button delete = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("delete"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                Object ref = contactTable.getValue();

                log.info("Delete Contact by ref: " + ref);

                if (ref != null) {
                    contactTable.getContainerDataSource().removeItem(ref);
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("contact.deleted"));
                } else
                    setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("nothing.to.do"));
            }
        });
        final Button undo = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("undo"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                formItem.discard();
            }
        });

        contactTable.addValueChangeListener(new Property.ValueChangeListener() {
            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                log.fine("Trying to change select in contact table");
                if (contactTable.getValue() != null) {
                    if (contactTable.getValue() instanceof String) changeURIFragment(1, (String)contactTable.getValue());

                    formItem.setItemDataSource(new BeanItem<Contact>(((JPAContainerItem<Contact>) contactTable.getItem(contactTable.getValue())).getEntity()));
                }
                log.fine("Change select in contact table.  New select is " + contactTable.getValue());
            }
        });
        final HorizontalLayout buttonsBar = new HorizontalLayout(saveAsNew, update, delete, undo);
        buttonsBar.setSizeUndefined();
        buttonsBar.setSpacing(true);
        final VerticalLayout detailFormWrapper = new VerticalLayout(detailedContactForm, buttonsBar);
        detailFormWrapper.setComponentAlignment(buttonsBar, Alignment.BOTTOM_RIGHT);
        detailFormWrapper.setComponentAlignment(detailedContactForm, Alignment.TOP_CENTER);
        detailFormWrapper.setSpacing(true);
        detailFormWrapper.setSizeFull();
        detailFormWrapper.setWidth("95%");

        contactTable.setWidth("95%");
        catalogTabForm.addComponent(contactTable);
        catalogTabForm.setComponentAlignment(contactTable, Alignment.TOP_CENTER);
        catalogTabForm.addComponent(detailFormWrapper);
        catalogTabForm.setSpacing(true);
        catalogTabForm.setMargin(true);
        catalogTabForm.setSizeFull();

        catalogTab = mainTab.addTab(catalogTabForm, ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("contacts"));
        catalogTab.setClosable(false);
    }

    private void createResumeTab() {


        //Preview panel

        final VerticalLayout previewPanel = new VerticalLayout();
        previewPanel.setSizeFull();
        previewPanel.setWidth("95%");
        previewPanel.setSpacing(true);

        //Resume table and buttons

        final JPAContainerForResume resumeList = new JPAContainerForResume();
        CachingMutableLocalEntityProvider<Resume> entityProvider =
                new CachingMutableLocalEntityProvider<Resume>(Resume.class, em);
        resumeList.setEntityProvider(entityProvider);

        Container.Filter userIdFilter = new Compare.Equal("userId", userId);
        resumeList.addContainerFilter(userIdFilter);
        resumeList.sort(new String[]{"date"}, new boolean[]{false});
        resumeList.applyFilters();
        resumeTable = new Table(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("list.of.resumes"), resumeList) {
            @Override
            protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) {
                if (property.getType() == GregorianCalendar.class) {
                    if (property.getValue() != null) {
                        return DateFormat.getDateInstance(DateFormat.SHORT, ((ResumeDBMaintUI) UI.getCurrent()).getUserLocale()).format(((GregorianCalendar) property.getValue()).getTimeInMillis());
                    } else return "";
                } else if (colId.equals("salary")) {
                    if (property.getValue() != null) {
                        NumberFormat nf = NumberFormat.getCurrencyInstance(((ResumeDBMaintUI) UI.getCurrent()).getUserLocale());
                        return nf.format(property.getValue());
                    } else return "0";
                }
                return super.formatPropertyValue(rowId, colId, property);
            }


        };

        resumeTable.addGeneratedColumn("open", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                Resume resume = ((EntityItem<Resume>) source.getItem(itemId)).getEntity();
                if (resume.getBody() != null) {
                    String openLink = null;
                    try {
                        openLink = resume.getBody().getOpenURL();
                    } catch (Exception e) {
                        log.warning("Error when get open link\n" + e.getMessage());
                    }
                    if (openLink != null && !openLink.isEmpty())
                        return new Link(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("open"), new ExternalResource(openLink));
                }
                return null;
            }
        });
        resumeTable.addGeneratedColumn("icon", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                Resume resume = ((EntityItem<Resume>) source.getItem(itemId)).getEntity();
                if (resume.getBody() != null) {
                    String iconLink = null;
                    try {
                        iconLink = resume.getBody().getThumbnailLink();
                    } catch (Exception e) {
                        log.warning("Error when get icon link\n" + e.getMessage());
                    }
                    if (iconLink != null && !iconLink.isEmpty()) {
                        Image icon = new Image("", new ExternalResource(iconLink));
                        float ratio = 0.71f; //A4 size
                        icon.setHeight(140, Sizeable.Unit.PIXELS);
                        icon.setWidth(140 * ratio, Sizeable.Unit.PIXELS);
                        return icon;
                    }
                }
                return null;
            }
        });
        resumeTable.setVisibleColumns("icon", "date", "position", "salary", "open");
        resumeTable.setWidth("100%");
        resumeTable.setHeight("100%");
        resumeTable.setColumnHeaders("", ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("created"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("position"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("salary"), "");
        resumeTable.setColumnAlignments(Table.Align.CENTER, Table.Align.CENTER, Table.Align.LEFT, Table.Align.CENTER, Table.Align.LEFT);
        resumeTable.setColumnExpandRatio("date", 1.5f);
        resumeTable.setColumnExpandRatio("position", 2f);
        resumeTable.setColumnExpandRatio("salaty", 1.8f);
        resumeTable.setColumnExpandRatio("icon", 2.5f);
        resumeTable.setColumnExpandRatio("open", 1.25f);
        resumeTable.setColumnReorderingAllowed(true);
        resumeTable.setSelectable(true);
        resumeTable.setMultiSelect(false);
        log.fine("resumeList firstItemId: " + resumeList.firstItemId());
        resumeTable.select(resumeList.firstItemId());
        resumeTable.setNullSelectionAllowed(true);
        resumeTable.setImmediate(true);
        resumeTable.setSortEnabled(false);
        resumeTableSortColumn = "date";
        resumeTableSortAsc = false;


        resumeTable.addHeaderClickListener(new Table.HeaderClickListener() {
            @Override
            public void headerClick(Table.HeaderClickEvent event) {
                String column = event.getPropertyId().toString();
                if (event.getButton() == MouseEventDetails.MouseButton.LEFT) {
                    if (column.equals("date")) {
                        if (resumeTableSortColumn.equals("date")) resumeTableSortAsc = !resumeTableSortAsc;
                        else {
                            resumeTableSortAsc = true;
                            resumeTableSortColumn = "date";
                        }
                        resumeTable.sort(new String[]{resumeTableSortColumn}, new boolean[]{resumeTableSortAsc});
                    }
                }
            }
        });


        //History area

        final JPAContainerForTracker historyContainer = new JPAContainerForTracker();
        CachingMutableLocalEntityProvider<resumeTracker> entityProviderTr =
                new CachingMutableLocalEntityProvider<resumeTracker>(resumeTracker.class, em);
        historyContainer.setEntityProvider(entityProviderTr);

        historyContainer.getEntityProvider().setQueryModifierDelegate(
                new DefaultQueryModifierDelegate() {
                    @Override
                    public void queryHasBeenBuilt(CriteriaBuilder criteriaBuilder, CriteriaQuery<?> query) {
                        log.fine("Filter query: " + query);
                        super.queryHasBeenBuilt(criteriaBuilder, query);
                    }

                    @Override
                    public void filtersWillBeAdded(CriteriaBuilder criteriaBuilder, CriteriaQuery<?> query, List<Predicate> predicates) {
                        Root<?> fromTracker = query.getRoots().iterator().next();

                        Path<String> id = fromTracker.<String>get("id");
                        log.fine("Filter builder: path_id is " + id);
                        log.fine("Filter builder: query is " + query);
                        for (Predicate p : predicates) {
                            log.fine("Filter builder: predicate " + p);
                            List<Expression<Boolean>> expressions = p.getExpressions();
                            if (expressions != null && expressions.size() > 0) {
                                for (Expression<Boolean> e : expressions) {
                                    log.fine("Op: " + p.getOperator());
                                    log.fine("Expression: " + e);
                                }
                            } else
                                log.fine("Predicate Op: " + p.getOperator());

                            String escpId = id.toString().replace(".", "\\.");
                            StringBuilder regex = new StringBuilder();
                            regex.append("^\\(");
                            regex.append(escpId);
                            regex.append("\\s+=\\s+'(\\S+)'\\)\\s*$");

                            Pattern mask = Pattern.compile(regex.toString());
                            if (p.getOperator() == Predicate.BooleanOperator.AND) {
                                Matcher matcher = mask.matcher(p.toString());
                                if (matcher.matches()) {
                                    log.fine("Found target predicate: " + p);
                                    String targetId = matcher.group(1);
                                    log.fine("Target id is " + targetId);
                                    Predicate newPredicate = criteriaBuilder.equal(id, targetId);
                                    log.fine("New predicate: " + newPredicate);
                                    predicates.clear();
                                    predicates.add(p);
                                    break;
                                }
                            }
                        }

                        super.filtersWillBeAdded(criteriaBuilder, query, predicates);
                    }
                });

        Object refResume = resumeTable.getValue();
        Container.Filter resumeIdFilter;
        if (refResume != null) {
            And filter = new And(new Compare.Equal("userId", userId),
                    new Compare.Equal("resume", ((EntityItem<Resume>) resumeTable.getItem(refResume)).getEntity().getId()));
            historyContainer.addContainerFilter(filter);
            drawPreview(previewPanel, resumeTable.getItem(refResume));
        }
        historyContainer.applyFilters();

        final Label detailHistoryArea = new Label("", ContentMode.HTML);
        detailHistoryArea.setSizeFull();
        final VerticalLayout historyAreaWrap = new VerticalLayout(detailHistoryArea);
        historyAreaWrap.setComponentAlignment(detailHistoryArea, Alignment.MIDDLE_CENTER);
        historyAreaWrap.setMargin(true);
        final Panel detailHistoryPanel = new Panel(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("details"), historyAreaWrap);
        detailHistoryPanel.setSizeFull();

        historyTable = new Table(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("sent.history")) {
            @Override
            protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) {
                if (property.getType() == GregorianCalendar.class) {
                    if (property.getValue() != null) {
                        return DateFormat.getDateInstance(DateFormat.SHORT, ((ResumeDBMaintUI) UI.getCurrent()).getUserLocale()).format(((GregorianCalendar) property.getValue()).getTimeInMillis());
                    } else return "";
                }
                return super.formatPropertyValue(rowId, colId, property);
            }
        };

        historyTable.addGeneratedColumn("call", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                resumeTracker tracker = ((EntityItem<resumeTracker>) source.getItem(itemId)).getEntity();
                return tracker.getNextRegularCallPresentation();
            }
        });
        historyTable.addGeneratedColumn("employer", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                resumeTracker tracker = ((EntityItem<resumeTracker>) source.getItem(itemId)).getEntity();
                Contact empl = getEmployer(tracker.getEmployer());
                if (empl != null) return (empl.getOrganization() != null && !empl.getOrganization().isEmpty())
                        ? empl.getOrganization() : empl.getName();
                return null;
            }
        });

        historyTable.setSizeFull();
        historyTable.setWidth("100%");
        historyTable.setHeight("100%");

        historyTable.addValueChangeListener(new Property.ValueChangeListener() {
            @Override
            public void valueChange(Property.ValueChangeEvent event) {

                Object ref = historyTable.getValue();
                log.fine("Change select in history table.  New select id is " + ref);
                if (ref != null) {
                    if (ref instanceof String) {
                        changeURIFragment(2, (String)ref);
                        changeURIFragment(1, (String)resumeTable.getValue());
                    }

                    StringBuilder historyContactDetailText = new StringBuilder();
                    resumeTracker ct = ((EntityItem<resumeTracker>) historyTable.getItem(ref)).getEntity();
                    Contact empl = getEmployer(ct.getEmployer());
                    if (empl != null) {
                        log.fine("Got Contact name: " + empl.getName());
                        historyContactDetailText.append(MessageFormat.format(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("p.b.person.nbsp.b.0.p.p.b.organization.nbsp.b.1.p.p.b.address.nbsp.b.2.p.table.tr.td.b.phones.nbsp.b.3.td.td.b.e.mails.nbsp.b.4.td.tr.table.p.b.comment.nbsp.b.5.p.hr"), empl.getName(), empl.getOrganization(), empl.getAddress(), empl.getPhones(), empl.getEmails(), empl.getComment()));
                    }
                    historyContactDetailText.append(MessageFormat.format(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("p.b.nextnbspcall.nbsp.b.0.p"), ct.getNextRegularCallPresentation()));
                    historyContactDetailText.append(MessageFormat.format(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("p.b.status.nbsp.b.0.p"), ct.getStatus()));
                    historyContactDetailText.append(MessageFormat.format(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("p.b.commentnbsptonbspsending.nbsp.b.0.p"), ct.getComment()));
                    detailHistoryArea.setValue(historyContactDetailText.toString());
                } else {
                    log.fine("Clear selection in history table");
                    detailHistoryArea.setValue("");
                }
            }
        });

        if (refResume != null && historyContainer.firstItemId() != null) {
            updateHistoryTable(historyContainer, historyTable);
        }


        final Button sentResume = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("send"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {

                final Object refResume = resumeTable.getValue();
                if (refResume != null) {
                    HistoryAddWindow historyEditor = new HistoryAddWindow(resumeTable.getItem(refResume), historyContainer);
                    historyEditor.addListener(new HistoryAddWindow.EditorSavedListener() {
                        @Override
                        public void editorSaved(HistoryAddWindow.EditorSavedEvent event) {

                            log.info("Register new sent record for resume " + ((EntityItem<resumeTracker>) event.getSavedItem()).getEntity().getResume());
                            Resume curResume = ((EntityItem<Resume>) resumeTable.getItem(refResume)).getEntity();
                            log.fine("Current resume is " + curResume);
                            historyTable.unselect(historyTable.getValue());
                            resumeTable.unselect(refResume);
                            resumeTable.select(refResume);
                            historyTable.select(((EntityItem<resumeTracker>) event.getSavedItem()).getItemId());
                        }
                    });
                    UI.getCurrent().addWindow(historyEditor);
                }
            }
        });

        final Button clearButton = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("clear.sending"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                Object ref = historyTable.getValue();
                Object refResume = resumeTable.getValue();
                if (ref != null && refResume != null) {
                    historyTable.removeItem(ref);
                    log.info("Deleted history record.  Id: " + ref);
                }
            }
        });

        final Button updateStatus = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("update.status"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                final Object refResume = resumeTable.getValue();
                final Object ref = historyTable.getValue();
                if (ref != null && refResume != null) {
                    Resume curResume = ((EntityItem<Resume>) resumeTable.getItem(refResume)).getEntity();
                    Item historyItem = historyTable.getItem(ref);
                    HistoryUpdateStatusWindow historyEditor = new HistoryUpdateStatusWindow(historyItem, curResume);
                    historyEditor.addListener(new HistoryUpdateStatusWindow.EditorSavedListener() {
                        @Override
                        public void editorSaved(HistoryUpdateStatusWindow.EditorSavedEvent event) {

                            log.info("Update sent record " + event.getSavedItem());
                            historyTable.unselect(ref);
                            historyTable.select(ref);
                        }
                    });
                    UI.getCurrent().addWindow(historyEditor);
                }
            }
        });

        final HorizontalLayout historyButtons = new HorizontalLayout(sentResume, clearButton, updateStatus);
        historyButtons.setSizeUndefined();
        historyButtons.setSpacing(true);


        final VerticalLayout historyPanel = new VerticalLayout(historyTable, detailHistoryPanel, historyButtons);
        historyPanel.setSizeFull();
        historyPanel.setSpacing(true);
        historyPanel.setComponentAlignment(historyTable, Alignment.TOP_CENTER);
        historyPanel.setComponentAlignment(detailHistoryPanel, Alignment.TOP_CENTER);
        historyPanel.setComponentAlignment(historyButtons, Alignment.BOTTOM_CENTER);
        historyTable.setWidth("95%");
        detailHistoryPanel.setWidth("95%");
        historyPanel.setExpandRatio(historyTable, 3);
        historyPanel.setExpandRatio(detailHistoryPanel, 6);
        historyPanel.setExpandRatio(historyButtons, 1);


        final Button buttonNew = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("new"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                Resume newResume = new Resume(userId, mine, 0, "");

                final BeanItem<Resume> newResumeItem = new BeanItem<Resume>(newResume);
                ResumeEditor resumeEditor = new ResumeEditor(newResumeItem, newResume);
                resumeEditor.addListener(new ResumeEditor.EditorSavedListener() {
                    @Override
                    public void editorSaved(ResumeEditor.EditorSavedEvent event) {
                        Resume newResume = ((BeanItem<Resume>) event.getSavedItem()).getBean();
                        log.info("Add new resume: " + newResume + " Blob object: " + newResume.getBody());
                        Object ref = resumeList.addEntity(newResume);
                        log.fine("Added new resume: " + ref);
                        resumeTable.select(ref);
                    }
                });
                UI.getCurrent().addWindow(resumeEditor);
            }
        });

        final Button buttonUpdate = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("edit"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                Object ref = resumeTable.getValue();
                if (ref != null) {
                    UI.getCurrent().addWindow(
                            new ResumeEditor(resumeTable.getItem(ref), ((EntityItem<Resume>) resumeTable.getItem(ref)).getEntity()));
                    resumeList.refreshItem(ref);
                    resumeTable.refreshRowCache();
                }
            }
        });

        final Button buttonDelete = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("delete"), new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                Object ref = resumeTable.getValue();
                if (ref != null) {
                    List<resumeTracker> history = (List<resumeTracker>) resumeTable.getItem(ref).getItemProperty("history").getValue();
                    if (history == null || history.isEmpty()) {
                        log.info("Delete resume record: (id) " + ref);
                        Resume res = ((EntityItem<Resume>) resumeTable.getItem(ref)).getEntity();
                        ResumeBlob blob = res.getBody();
                        if (blob != null)
                            try {
                                if (blob.deleteBlob()) {
                                    EntityManager em = JPAContainerFactory.createEntityManagerForPersistenceUnit(EMF.PERSISTENCE_UNIT);
                                    blob = em.merge(blob);
                                    em.remove(blob);
                                    em.close();
                                    resumeList.removeItem(ref);
                                } else
                                    Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("error.when.deleting.blob"), Notification.Type.ERROR_MESSAGE);
                            } catch (Exception e) {
                                log.warning(e.toString());
                                Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("delete.blob.error.n"), e.getMessage(), Notification.Type.ERROR_MESSAGE);
                            }
                        else resumeList.removeItem(ref);
                        refreshPreviewResume(previewPanel, new ArrayList<Component>());
                    } else
                        Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("can.t.delete.resume.with.non.empty.history"), Notification.Type.ERROR_MESSAGE);
                }
            }
        });

        resumeTable.addValueChangeListener(new Property.ValueChangeListener() {
            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                Object ref = resumeTable.getValue();
                if (ref != null) {
                    if (ref instanceof String) changeURIFragment(1, (String)ref);

                    drawPreview(previewPanel, resumeTable.getItem(ref));

                    historyTable.unselect(historyTable.getValue());
                    historyContainer.removeAllContainerFilters();
                    And filter = new And(new Compare.Equal("userId", userId),
                            new Compare.Equal("resume", ((EntityItem<Resume>) resumeTable.getItem(ref)).getEntity().getId()));
                    historyContainer.addContainerFilter(filter);

                    historyContainer.applyFilters();
                    if (historyContainer.firstItemId() != null) {
                        updateHistoryTable(historyContainer, historyTable);
                        historyTable.select(historyTable.firstItemId());
                    } else {
                        log.fine("Clear selection in resume table 2");
                        historyTable.setContainerDataSource(null);
                    }

                    log.fine("Change select in resume Table to " + ref);
                    log.fine("History table selection: " + historyTable.getValue());
                    log.fine("History size is " + historyContainer.size());
                    log.fine("History list size in Resume is " + ((List<Resume>) resumeTable.getItem(resumeTable.getValue()).getItemProperty("history").getValue()).size());
                } else {
                    log.fine("Clear selection in resume table");
                    historyTable.setContainerDataSource(null);
                }
            }
        });

        final HorizontalLayout resumeButtons = new HorizontalLayout(buttonNew, buttonUpdate, buttonDelete);
        resumeButtons.setSizeUndefined();
        resumeButtons.setSpacing(true);

        final VerticalLayout leftResumePanel = new VerticalLayout(resumeTable, resumeButtons);
        leftResumePanel.setComponentAlignment(resumeButtons, Alignment.BOTTOM_CENTER);
        leftResumePanel.setComponentAlignment(resumeTable, Alignment.TOP_CENTER);
        leftResumePanel.setSizeFull();
        leftResumePanel.setExpandRatio(resumeTable, 90);
        resumeTable.setWidth("95%");
        leftResumePanel.setExpandRatio(resumeButtons, 10);

        final HorizontalSplitPanel resumeAndPreviewPane = new HorizontalSplitPanel();
        final HorizontalSplitPanel resumeTabForm = new HorizontalSplitPanel();
        resumeTabForm.setSizeFull();
        resumeAndPreviewPane.setSizeFull();

        resumeTabForm.addComponents(leftResumePanel, historyPanel);
        resumeAndPreviewPane.addComponents(resumeTabForm, previewPanel);
        float maxSplit = resumeAndPreviewPane.getMaxSplitPosition();
        resumeAndPreviewPane.setSplitPosition(maxSplit * 0.70f);

/*
        resumeTabForm.setSpacing(true);
        resumeTabForm.setMargin(true);
        resumeTabForm.setExpandRatio(leftResumePanel, 2);
        resumeTabForm.setExpandRatio(historyPanel, 2);
        resumeTabForm.setExpandRatio(previewPanel, 3.5f);
        resumeTabForm.setComponentAlignment(leftResumePanel, Alignment.TOP_CENTER);
        resumeTabForm.setComponentAlignment(historyPanel, Alignment.TOP_CENTER);
        resumeTabForm.setComponentAlignment(previewPanel, Alignment.TOP_CENTER);
*/


        resumeTab = mainTab.addTab(resumeAndPreviewPane, ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("resumes"));
        resumeTab.setClosable(false);
        resumeTab.setVisible(true);
    }

    private void changeURIFragment(int i, String ref) {
        String[] fragments = pageFragments.toString().split("&");
        if (fragments.length > i) {
            fragments[i] = ref;
        } else {
            String[] fragments2 = new String[i+1];
            Arrays.fill(fragments2, fragments.length, i, "");
            fragments2[i] = ref;
            for (int j = 0; j < fragments.length; j++) fragments2[j] = fragments[j];
            fragments = fragments2;
        }
        pageFragments = new StringBuffer();
        for (String s : fragments) pageFragments.append(s + "&");
        if (pageFragments.length() > 0) pageFragments.deleteCharAt(pageFragments.length()-1);
        Page.getCurrent().setUriFragment("!/" + pageFragments.toString(), false);
    }

    private void updateHistoryTable(JPAContainerForTracker historyContainer, Table historyTable) {
        historyTable.setContainerDataSource(historyContainer);
        historyTable.setSelectable(true);
        historyTable.setNullSelectionAllowed(true);
        historyTable.setImmediate(true);
        historyTable.setSortEnabled(true);

        historyTable.setColumnCollapsingAllowed(true);

//                historyTable.setVisibleColumns("sentdate", "checkcall", "nextcall", "status");
        historyTable.setVisibleColumns("employer", "sentdate", "call", "status");
        historyTable.setColumnHeaders(
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("organization.name"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("sent.date"),
//                        ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("check.date"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("next.call"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("status"));
//                historyTable.setColumnAlignments(Table.Align.CENTER, Table.Align.CENTER, Table.Align.CENTER, Table.Align.LEFT);
        historyTable.setColumnAlignments(Table.Align.LEFT, Table.Align.CENTER, Table.Align.CENTER, Table.Align.LEFT);
        historyTable.setColumnExpandRatio("employer", 1.2f);
        historyTable.setColumnExpandRatio("sentdate", 1f);
//                historyTable.setColumnExpandRatio("checkcall", 1.2f);
        historyTable.setColumnExpandRatio("call", 1.2f);
        historyTable.setColumnExpandRatio("status", 2f);
        historyTable.setColumnCollapsible("employer", false);
/*
        historyTable.setColumnCollapsible("sentdate", false);
        historyTable.setColumnCollapsible("call", true);
        historyTable.setColumnCollapsible("status", true);
*/
        historyContainer.sort(new String[]{"sentdate"}, new boolean[]{false});

        historyTable.select(historyTable.firstItemId());
        log.fine("History size is " + historyContainer.size());
        log.fine("History selection is " + historyTable.getValue());
    }

    private void createUserInfoLabel() {
        userInfoBar = new GridLayout(2, 2);
        userInfoBar.setSizeUndefined();

        Image userPictire = new Image(null, services.getUserIcon());
        userPictire.setWidth("40px");
        userPictire.setHeight("40px");
        userInfoBar.addComponent(userPictire, 1, 0, 1, 1);
        userInfoBar.setComponentAlignment(userPictire, Alignment.MIDDLE_LEFT);


        Label userLabel = new Label(services.getUserName());
        userLabel.setSizeUndefined();
        userInfoBar.addComponent(userLabel, 0, 0);
        userInfoBar.setComponentAlignment(userLabel, Alignment.TOP_RIGHT);

        Link logoutLink = new Link(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("logout"), new ExternalResource(UserServiceFactory.getUserService().createLogoutURL(rootUrl)));
        logoutLink.setSizeUndefined();

        userInfoBar.addComponent(logoutLink, 0, 1);
        userInfoBar.setComponentAlignment(logoutLink, Alignment.TOP_RIGHT);
        userInfoBar.setSpacing(true);
    }

    private void createMainMenu() {
        final MenuBar.MenuItem operationsMenu = bar.addItem(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("operations"), null, null);

        operationsMenu.addItem(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("clear.google.services.access.status"), new MenuBar.Command() {
            @Override
            public void menuSelected(MenuBar.MenuItem selectedItem) {
                ((ResumeDbMainServlet) ResumeDbMainServlet.getCurrent()).dropCredential();
                Notification.show(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("current.page.needs.to.reload"), Notification.Type.WARNING_MESSAGE);
                Page.getCurrent().setLocation(rootUrl);
            }
        });

        operationsMenu.addItem(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("refresh.todo"), new MenuBar.Command() {
            @Override
            public void menuSelected(MenuBar.MenuItem selectedItem) {
                refreshTodoListForUser(userId);
                refreshTodayTab();
            }
        });

        operationsMenu.addSeparator();

        operationsMenu.addItem(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("logout"), new MenuBar.Command() {
            @Override
            public void menuSelected(MenuBar.MenuItem selectedItem) {
                Page.getCurrent().setLocation(UserServiceFactory.getUserService().createLogoutURL(rootUrl));
            }
        });

        bar.setSizeUndefined();
    }

    private void refreshTodayTab() {
        //TODO wait new todo list and refresh today content
        setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("tasks.update.waiting"));
    }

    private void refreshTodayContent() {

        TodoList todo = getToDo(userId);
        log.info("Got TODO: " +  todo);

        if (todo != null && !todo.getEvents().isEmpty()) {
            HorizontalLayout horizontalLayout = new HorizontalLayout();
            horizontalLayout.setDefaultComponentAlignment(Alignment.TOP_CENTER);
            horizontalLayout.setSizeFull();
            horizontalLayout.setMargin(true);
            horizontalLayout.setSpacing(true);
            horizontalLayout.addComponent(createActualEventsTable(new BeanItemContainer<study.alex.resumedb.gae.model.Event>(study.alex.resumedb.gae.model.Event.class, todo.getActual())));

            VerticalLayout verticalLayout = new VerticalLayout();
            verticalLayout.setDefaultComponentAlignment(Alignment.TOP_CENTER);
            verticalLayout.setSizeUndefined();
//            verticalLayout.setMargin(true);
            verticalLayout.setSpacing(true);
            verticalLayout.addComponent(createLateEventsTable(new BeanItemContainer<study.alex.resumedb.gae.model.Event>(study.alex.resumedb.gae.model.Event.class, todo.getLate())));
            verticalLayout.addComponent(createSoonEventsTable(new BeanItemContainer<study.alex.resumedb.gae.model.Event>(study.alex.resumedb.gae.model.Event.class, todo.getSoon())));

            horizontalLayout.addComponent(verticalLayout);
            todayContent.removeAllComponents();
            todayContent.addComponent(horizontalLayout);
        } else {
            Panel panel;
            Label nothingLabel = new Label(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("dont.have.any.task"));
            nothingLabel.setStyleName(Runo.LABEL_H1);
            panel = new Panel(nothingLabel);
            panel.setSizeUndefined();
            panel.setStyleName(Runo.PANEL_LIGHT);
            todayContent.removeAllComponents();
            todayContent.addComponent(panel);
        }
    }

    private TodoList getToDo(String userId) {
        if (userId == null || userId.isEmpty()) return null;
        EntityManager em = EMF.getEntityManager();

        try{
            Query q = em.createQuery(String.format("SELECT t FROM %s t WHERE t.userId = '%s'", TodoList.class.getName(), userId), TodoList.class);
            List<TodoList> result = q.getResultList();
            if (result == null || result.isEmpty()) return null;
            else return result.get(0);
        } finally {
            em.close();
        }
    }

    private Component createSoonEventsTable(BeanItemContainer<study.alex.resumedb.gae.model.Event> container) {
        String caption = ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("soon.todo");
        Table table = createEventsTable(container, caption);
        table.setPageLength(5);
        return table;
    }

    private Table createLateEventsTable(BeanItemContainer<study.alex.resumedb.gae.model.Event> container) {
        String caption = ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("late.todo");
        Table table = createEventsTable(container, caption);
        table.setPageLength(15);
        return table;
    }

    private Table createActualEventsTable(BeanItemContainer<study.alex.resumedb.gae.model.Event> container) {
        String caption = ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("actual.todo");
        Table table = createEventsTable(container, caption);
        table.setPageLength(10);
        return table;
    }

    private Table createEventsTable(BeanItemContainer<study.alex.resumedb.gae.model.Event> container, String caption) {
        Table table = new Table(caption, container){
            @Override
            protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) {
                if (property.getType() == GregorianCalendar.class) {
                    if (property.getValue() != null) {
                        return DateFormat.getDateInstance(DateFormat.SHORT, ((ResumeDBMaintUI) UI.getCurrent()).getUserLocale()).format(((GregorianCalendar) property.getValue()).getTimeInMillis());
                    } else return "";
                }
                return super.formatPropertyValue(rowId, colId, property);
            }
        };
        table.addGeneratedColumn("employer", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                String contactId = ((BeanItem<study.alex.resumedb.gae.model.Event>) source.getItem(itemId)).getBean().getEventContactId();
                Contact empl = getEmployer(contactId);
                if (empl == null) return null;
                String emplLabel = (empl.getOrganization() != null && !empl.getOrganization().isEmpty())
                                                                            ? empl.getOrganization() : empl.getName();
                return emplLabel;
            }
        });
        table.addGeneratedColumn("history", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                String trackerId = ((BeanItem<study.alex.resumedb.gae.model.Event>) source.getItem(itemId)).getBean().getTrackerId();
                final resumeTracker tr = getHistory(trackerId);
                if (tr == null) return null;
                Button historyButton = new Button(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("history.label.todo"));
                historyButton.addClickListener(new Button.ClickListener() {

                    @Override
                    public void buttonClick(Button.ClickEvent event) {

                        Resume resume = tr.getResume();
                        Item historyItem = new BeanItem<resumeTracker>(tr);
                        HistoryUpdateStatusWindow historyEditor = new HistoryUpdateStatusWindow(historyItem, resume);

                        historyEditor.addListener(new HistoryUpdateStatusWindow.EditorSavedListener() {
                            @Override
                            public void editorSaved(HistoryUpdateStatusWindow.EditorSavedEvent event) {

                                log.info("Update sent record " + event.getSavedItem());
                                resumeTracker tr = ((BeanItem<resumeTracker>)event.getSavedItem()).getBean();
                                EntityManager em = EMF.getEntityManager();
                                try {
                                    em.merge(tr);
                                } finally {
                                    em.close();
                                }
                            }
                        });
                        UI.getCurrent().addWindow(historyEditor);
                    }
                });
                historyButton.setStyleName(Runo.BUTTON_SMALL);
                return historyButton;
            }
        });

        table.addGeneratedColumn("salary", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                String trackerId = ((BeanItem<study.alex.resumedb.gae.model.Event>) source.getItem(itemId)).getBean().getTrackerId();
                final resumeTracker tr = getHistory(trackerId);
                if (tr == null) return null;
                Resume resume = tr.getResume();
                NumberFormat nf = NumberFormat.getCurrencyInstance(((ResumeDBMaintUI) UI.getCurrent()).getUserLocale());
                return nf.format(resume.getSalary());
            }
        });
        table.addGeneratedColumn("position", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                String trackerId = ((BeanItem<study.alex.resumedb.gae.model.Event>) source.getItem(itemId)).getBean().getTrackerId();
                final resumeTracker tr = getHistory(trackerId);
                if (tr == null) return null;
                Resume resume = tr.getResume();
                return resume.getPosition();
            }
        });
        table.addGeneratedColumn("resumelink", new Table.ColumnGenerator() {
            @Override
            public Object generateCell(Table source, Object itemId, Object columnId) {
                if (itemId == null) return null;
                String trackerId = ((BeanItem<study.alex.resumedb.gae.model.Event>) source.getItem(itemId)).getBean().getTrackerId();
                final resumeTracker tr = getHistory(trackerId);
                if (tr == null) return null;
                Resume resume = tr.getResume();
                ResumeBlob blob = resume.getBody();
                Label noBlob = new Label(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("no.blob"));
                if (blob == null) return noBlob;
                Link blobLink;
                try {
                    blobLink = new Link(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("open.resume"),
                            new ExternalResource(blob.getOpenURL()), "_blank",
                            getUIWidthInPixels(),
                            getUIHeightInPixels(),
                            BorderStyle.DEFAULT);
                } catch (ResumeBlobException e) {
                    log.warning("Can't get open link for blob(1) " + e.getMessage());
                    return noBlob;
                } catch (IOException e) {
                    log.warning("Can't get open link for blob(2) " + e.getMessage());
                    return noBlob;
                }
                return blobLink;
            }
        });

        table.setVisibleColumns("type", "date", "employer", "position", "salary", "history", "resumelink");
        table.setColumnAlignments(Table.Align.CENTER, Table.Align.CENTER, Table.Align.LEFT, Table.Align.LEFT,
                                    Table.Align.CENTER, Table.Align.CENTER, Table.Align.CENTER);
        table.setColumnHeaders(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("todo.label.type"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("todo.label.date"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("organization.name"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("position"),
                ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("salary"),
                "",
                "");
        table.setSortEnabled(false);
        table.setSelectable(false);
        table.sort(new String[]{"date"}, new boolean[]{false});

        return table;
    }

    private int getUIHeightInPixels() {
        return Page.getCurrent().getWebBrowser().getScreenHeight()*90/100;
    }

    private int getUIWidthInPixels() {
        return Page.getCurrent().getWebBrowser().getScreenWidth()*90/100;
    }

    private void refreshTodoListForUser(String userId) {
        BackendService service = BackendServiceFactory.getBackendService();
        String backendServiceAddress = service.getBackendAddress("worker");
        log.info("Backend address is " + backendServiceAddress);

        URL url;
        try {
            url = new URL("https", backendServiceAddress,
                    String.format("/tasks/TODO/?userId=%s", URLEncoder.encode(userId, "UTF-8")));
        } catch (MalformedURLException e) {
            log.severe("Malformed backend address: " + backendServiceAddress);
            e.printStackTrace();
            return;
        } catch (UnsupportedEncodingException e) {
            log.severe("Encoding query parameter to UTF-8 not supported");
            e.printStackTrace();
            return;
        }

//        httpResponseFuture = fetchService.fetchAsync(url);
        HTTPRequest httpRequest = new HTTPRequest(url, HTTPMethod.GET, FetchOptions.Builder.followRedirects());
        HTTPResponse httpResponse;
        try {
            httpResponse = fetchService.fetch(httpRequest);
        } catch (IOException e) {
            log.severe("Error(3) when touch backend service. " + e.getMessage());
            e.printStackTrace();
            return;
        }
        log.info("Backend service url is " + url);
        log.info("HTTP Status is " + httpResponse.getResponseCode());
    }

    private void drawPreview(final VerticalLayout panel, final Item item) {
        final Resume currentResume = ((EntityItem<Resume>) item).getEntity();

        log.fine("Making preview for " + currentResume);
        List<Component> previews;
        int previewWidth = 200;
        float width = (int) panel.getWidth();
        Sizeable.Unit unit = panel.getWidthUnits();
        if (unit == Sizeable.Unit.PIXELS) previewWidth = (int) (width * 0.9);
        previews = previewResume(currentResume, previewWidth);  //previewResume is synchronized method
        log.fine("Returned preview: " + previews);
        refreshPreviewResume(panel, previews);
    }


    private void refreshPreviewResume(final VerticalLayout panel, final Collection<Component> cont) {
        if (parent != null) parent.access(new Runnable() {
            @Override
            public void run() {
                panel.removeAllComponents();
                panel.setDefaultComponentAlignment(Alignment.TOP_CENTER);
                panel.setSpacing(true);
                for (Component c : cont) panel.addComponent(c);
                setStatusbar(((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("preview.updated"));
                log.fine("Preview updated.  Count components: " + panel.getComponentCount());
            }
        });

    }

    private List<Component> previewResume(Resume currentResume, int previewWidth) {


        List<Component> previews = new ArrayList<Component>();
        final int previewHeight = (int) (previewWidth / 0.7f);  // A4 size

        if (currentResume != null) {
            ResumeBlob blob = currentResume.getBody();
            if (blob != null) {
                try {
                    String url = blob.getPreviewURL();
                    if (url != null && !url.isEmpty()) {
                        BrowserFrame object = new BrowserFrame("", new ExternalResource(url));
                        object.setWidth("100%");
                        object.setHeight("100%");
                        previews.add(object);
                    } else
                        previews = Arrays.asList(createBlankPreview(previewWidth, previewHeight, "2"));
                } catch (Exception e) {
                    log.fine("Can't get preview URL\n" + e.toString());
                    previews = Arrays.asList(createBlankPreview(previewWidth, previewHeight, "1"));
                }
            } else previews = Arrays.asList(createBlankPreview(previewWidth, previewHeight, "2"));
        } else previews = Arrays.asList(createBlankPreview(previewWidth, previewHeight, "3"));
        return previews;
    }

    private Component createBlankPreview(int previewWidth, int previewHeight, String s) {

        log.fine("Creating blank preview: " + s + " width=" + previewWidth);

        String imageFile;
        int sel = Integer.valueOf(s);

        switch (sel) {
            case 1:
                imageFile = ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("blank.error");
                break;
            case 3:
                imageFile = ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("blank.not.available");
                break;
            case 2:
            default:
                imageFile = ((ResumeDBMaintUI) UI.getCurrent()).getBundle().getString("blank.not.found");
                break;
        }
        Resource source = new ClassResource(ResumeDBMaintUI.class, imageFile);
        Image img = new Image("", source);
        log.fine("phase 4");
        img.setWidth(previewWidth, Sizeable.Unit.PIXELS);
        img.setHeight(previewHeight, Sizeable.Unit.PIXELS);

        log.fine("Created: " + img);
        return img;
    }


    private Contact getEmployer(String id) {
        if (id == null || id.isEmpty()) return null;
        EntityManager em = JPAContainerFactory.createEntityManagerForPersistenceUnit(EMF.PERSISTENCE_UNIT);

        try {
            Contact ct = em.find(Contact.class, id);
/*
            Query q = em.createQuery("SELECT cont FROM study.alex.resumedb.gae.model.Contact cont WHERE cont.id = '" + id + "'", Contact.class);
            List<Contact> list = (List<Contact>)q.getResultList();
*/
            log.fine("Got Contact info: " + ct);
//                if (list != null && list.size() > 0) return list.get(0);
//                else return null;
            return ct;
        } finally {
            em.close();
        }
    }

    private resumeTracker getHistory(String id) {
        if (id == null || id.isEmpty()) return null;
        EntityManager em = JPAContainerFactory.createEntityManagerForPersistenceUnit(EMF.PERSISTENCE_UNIT);

        try {
            resumeTracker tracker = em.find(resumeTracker.class, id);
            log.fine("Got Tracker info: " + tracker);
            return tracker;
        } finally {
            em.close();
        }
    }

    public void setStatusbar(final String msg) {

        if (parent != null) parent.access(new Runnable() {
            @Override
            public void run() {
                if (statusbar != null) statusbar.setValue(msg);
            }
        });
    }

}